공유 메모리 시스템

AI
gemma-4-31b
작성자
익명
작성일
2026.07.13
조회수
1
버전
v1

공유 메모리 시스템 (Shared Memory System)

1. 개요

공유 메모리 시스템은 여러 개의 프로세서나 독립적인 프로세스들이 하나의 공통된 물리적 메모리 주소 공간을 공유하여 데이터를 읽고 쓸 수 있도록 설계된 컴퓨터 메모리 아키텍처이다. 이 시스템의 핵심 목적은 프로세스 간 통신(IPC, Inter-Process Communication) 시 데이터를 복사하는 오버헤드를 최소화하여 데이터 교환 속도를 극대화하는 데 있다.

2. 동작 원리 및 구조

공유 메모리 시스템에서는 운영체제가 특정 메모리 영역을 '공유 영역'으로 지정하고, 이를 필요로 하는 여러 프로세스의 가상 주소 공간(Virtual Address Space)에 매핑한다. 이를 통해 각 프로세스는 자신의 메모리에 접근하듯 공유 영역에 직접 접근하여 데이터를 읽거나 쓸 수 있다.

2.1 데이터 접근 흐름

  1. 영역 생성: 운영체제가 커널 수준에서 공유 메모리 세그먼트를 할당한다.
  2. 매핑(Attach): 각 프로세스가 자신의 주소 공간에 해당 세그먼트를 연결한다.
  3. 직접 접근: 프로세스가 포인터를 통해 공유 메모리에 직접 데이터를 쓰고 읽는다.
  4. 해제(Detach): 사용이 완료된 프로세스는 매핑을 해제하고, 마지막 프로세스가 종료되면 메모리가 회수된다.

2.2 공유 메모리 vs 메시지 패싱 비교

구분 공유 메모리 (Shared Memory) 메시지 패싱 (Message Passing)
통신 방식 공통 메모리 영역에 직접 읽기/쓰기 send()receive() 함수 호출
데이터 복사 복사 없음 (포인터 참조) 커널을 통한 데이터 복사 발생
속도 매우 빠름 (메모리 접근 속도) 상대적으로 느림 (시스템 콜 오버헤드)
동기화 사용자가 직접 구현 (뮤텍스 등) 통신 메커니즘 자체에 내장됨
확장성 단일 시스템 내에서 유리 분산 시스템(네트워크)으로 확장 가능

3. 주요 아키텍처 분류

메모리 접근 시간의 균일성 여부에 따라 크게 UMANUMA로 분류한다.

3.1 UMA (Uniform Memory Access)

모든 프로세서가 모든 메모리 위치에 접근하는 시간이 동일한 구조이다. 주로 SMP(Symmetric Multiprocessing) 시스템에서 사용되며, 구조가 단순하지만 프로세서 수가 증가할수록 메모리 버스의 병목 현상이 심화되는 단점이 있다.

[UMA 구조 도식]

[ 프로세서 1 ]   [ 프로세서 2 ]   [ 프로세서 3 ]   [ 프로세서 4 ]
      |               |               |               |
      +---------------+---------------+---------------+
                              |
                      [ 시스템 버스 (Bus) ]
                              |
                      [ 공통 물리 메모리 ]

3.2 NUMA (Non-Uniform Memory Access)

각 프로세서가 자신에게 물리적으로 가까운 '로컬 메모리'를 가지며, 다른 프로세서의 메모리에는 네트워크나 인터커넥트를 통해 접근하는 구조이다. 로컬 메모리 접근은 빠르지만 원격 메모리 접근은 느리다. 이는 대규모 서버나 고성능 컴퓨팅(HPC) 시스템에서 확장성을 높이기 위해 채택된다.

[NUMA 구조 도식]

[ 프로세서 1 ] <---> [ 로컬 메모리 1 ]       [ 프로세서 2 ] <---> [ 로컬 메모리 2 ]
      ^                                           ^
      |                                           |
      +----------------- [ 인터커넥트 ] -----------+
                                |
[ 프로세서 3 ] <---> [ 로컬 메모리 3 ]       [ 프로세서 4 ] <---> [ 로컬 메모리 4 ]

4. 캐시 일관성 및 메모리 배리어

멀티코어 환경에서는 각 코어가 성능 향상을 위해 개별 L1, L2 캐시를 가지므로, 동일한 메모리 주소의 값이 여러 캐시에 복제되어 데이터 불일치가 발생할 수 있다.

4.1 캐시 일관성 프로토콜 (Cache Coherence Protocol)

캐시 일관성이란 모든 코어가 항상 최신 데이터를 읽을 수 있도록 보장하는 메커니즘이다. - Snooping: 모든 캐시 컨트롤러가 버스를 감시(Snooping)하여, 자신이 가진 데이터가 수정되면 다른 캐시의 복사본을 무효화(Invalidate)하거나 갱신하는 방식이다. - Directory-based: 중앙 디렉토리에 어떤 캐시가 어떤 블록을 가지고 있는지 기록하여, 변경 사항이 있을 때 해당 캐시들에만 알림을 보내는 방식이다. (NUMA 구조에서 주로 사용) - MESI 프로토콜: 가장 대표적인 프로토콜로, 캐시 라인의 상태를 Modified(수정), Exclusive(독점), Shared(공유), Invalid(무효)의 4가지 상태로 구분하여 관리함으로써 일관성을 유지한다.

4.2 메모리 배리어 (Memory Barrier / Fence)

현대 CPU와 컴파일러는 성능 최적화를 위해 명령어의 실행 순서를 바꾸는 비순차적 실행(Out-of-order Execution)을 수행한다. 메모리 배리어는 특정 지점 이전의 메모리 작업이 반드시 완료된 후에 다음 작업이 수행되도록 강제하는 하드웨어 명령어로, 멀티스레드 환경에서 데이터 가시성을 보장하는 데 필수적이다.

5. 동기화 문제와 해결 방안

여러 주체가 동시에 공유 메모리에 접근할 때, 실행 순서에 따라 결과가 달라지는 경쟁 상태(Race Condition)가 발생한다. 이를 방지하기 위해 임계 구역(Critical Section)을 보호하는 동기화 기법이 필요하다.

  • 뮤텍스 (Mutex): 상호 배제(Mutual Exclusion)의 약자로, 한 번에 하나의 프로세스만 공유 자원에 접근할 수 있도록 잠금(Lock)을 거는 방식이다.
  • 세마포어 (Semaphore): 정수 값을 사용하여 공유 자원의 개수를 관리하며, 신호(Signal)를 통해 프로세스의 진입과 퇴장을 제어한다.
  • 스핀락 (Spinlock): 락을 획득할 때까지 루프를 돌며 대기하는 방식으로, 대기 시간이 매우 짧을 때 컨텍스트 스위칭 비용을 줄이기 위해 사용한다.

주의 사항: 동기화 기법을 사용할 때 락을 획득하는 순서가 잘못되면, 모든 프로세스가 서로가 가진 락이 해제되기를 기다리며 무한 대기하는 데드락(Deadlock) 상태가 발생할 수 있다. 이를 방지하기 위해 엄격한 락 획득 순서 정립이 중요하다.

6. 계층 구조도

공유 메모리 시스템의 하드웨어와 소프트웨어 간의 상호작용 계층은 다음과 같다.

[ 소프트웨어 계층 ]
      ↑
  Application (프로세스 A, B, C)  <-- [동기화: Mutex, Semaphore]
      ↓
  OS Kernel (가상 메모리 관리, 페이지 테이블 매핑)
      ↓
[ 하드웨어 계층 ]
      ↑
  Memory Management Unit (MMU) / Cache Controller
      ↓
  Physical Memory (Shared RAM) / Interconnect (Bus, QPI, UPI)

7. 장단점 및 활용 사례

7.1 장단점

  • 장점:
    • 고속 통신: 커널을 거치지 않고 메모리에 직접 접근하므로 데이터 전송 지연 시간이 극히 짧다.
    • 효율성: 대량의 데이터를 주고받을 때 복사 과정이 없어 CPU 및 메모리 자원 소모가 적다.
  • 단점:
    • 동기화 복잡성: 개발자가 직접 락(Lock)을 관리해야 하며, 잘못 구현할 경우 데드락(Deadlock)이 발생할 수 있다.
    • 보안 위험: 공유 영역에 대한 접근 제어가 정교하지 않으면 데이터 오염 가능성이 있다.
    • 하드웨어 제약: UMA의 경우 프로세서 증가 시 버스 병목 현상이 발생하며, NUMA의 경우 원격 메모리 접근 시 성능 저하가 발생한다.

7.2 활용 사례

  • 멀티코어 프로세서: L3 캐시 공유 및 코어 간 데이터 교환.
  • 고성능 컴퓨팅(HPC): 대규모 수치 해석 및 시뮬레이션 소프트웨어.
  • 데이터베이스 시스템: 공유 버퍼 풀(Shared Buffer Pool)을 통해 여러 쿼리 프로세스가 동일한 데이터 페이지에 접근.

8. 구현 예시

8.1 System V Shared Memory (Legacy)

C 언어의 System V 표준을 이용한 공유 메모리 생성 및 접근의 기본 흐름이다.

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>

int main() {
    key_t key = ftok("shmfile", 65);
    int shmid = shmget(key, 1024, 0666 | IPC_CREAT);
    char *str = (char*) shmat(shmid, (void*)0, 0);

    strcpy(str, "Hello, System V Shared Memory!");
    printf("Data written: %s\n", str);

    shmdt(str);
    return 0;
}

8.2 POSIX Shared Memory (Modern)

shm_open<a href="/doc/%EA%B8%B0%EC%88%A0/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D/API/mmap" class="wiki-link">mmap</a>을 사용하는 현대적인 POSIX 표준 방식이다.

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <string.h>

int main() {
    const char *name = "/my_shm";
    const int SIZE = 1024;

    // 1. 공유 메모리 객체 생성
    int shm_fd = shm_open(name, O_CREAT | O_RDWR, 0666);
    
    // 2. 공유 메모리 크기 설정
    ftruncate(shm_fd, SIZE);

    // 3. 프로세스 주소 공간에 매핑
    void *ptr = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);

    // 4. 데이터 쓰기
    sprintf(ptr, "Hello, POSIX Shared Memory!");
    printf("Data written: %s\n", (char*)ptr);

    // 5. 해제 및 제거
    munmap(ptr, SIZE);
    close(shm_fd);
    shm_unlink(name);

    return 0;
}
위 코드는 단순화된 예시이며, 실제 환경에서는 세마포어를 이용한 동기화 로직이 반드시 추가되어야 한다.

AI 생성 콘텐츠 안내

이 문서는 AI 모델(gemma-4-31b)에 의해 생성된 콘텐츠입니다.

주의사항: AI가 생성한 내용은 부정확하거나 편향된 정보를 포함할 수 있습니다. 중요한 결정을 내리기 전에 반드시 신뢰할 수 있는 출처를 통해 정보를 확인하시기 바랍니다.

이 AI 생성 콘텐츠가 도움이 되었나요?